﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Runtime.Serialization.Formatters.Binary;
using MyLib.Data;

namespace MyLib.Web {
	/// <summary>
	/// 
	/// </summary>
	public abstract class MyPage : System.Web.UI.Page {
		private const string CONST_CODE_FILE_NAME = @"~/ConstSysCode.xml";

		/// <summary>
		/// 
		/// </summary>
		protected log4net.ILog m_logger;

		private IList<string> m_errorMessages;

		private IList<string> m_warningMessage;

		private IList<string> m_infoMessages;

		/// <summary>
		/// 
		/// </summary>
		protected MyPage() {
			m_logger = log4net.LogManager.GetLogger(GetType());
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="errorMessage"></param>
		protected internal void AddError(string errorMessage) {
			if (m_errorMessages == null)
				m_errorMessages = new List<string>();

			m_errorMessages.Add(errorMessage);
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="format"></param>
		/// <param name="args"></param>
		protected internal void AddError(string format, params object[] args) {
			if (string.IsNullOrWhiteSpace(format))
				return;
			else
				AddError(string.Format(format, args));
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="warningMessage"></param>
		protected internal void AddWarning(string warningMessage) {
			if (m_warningMessage == null)
				m_warningMessage = new List<string>();

			m_warningMessage.Add(warningMessage);
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="format"></param>
		/// <param name="args"></param>
		protected internal void AddWarning(string format, params object[] args) {
			if (string.IsNullOrWhiteSpace(format))
				return;
			else
				AddWarning(string.Format(format, args));
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="inforMessage"></param>
		protected internal void AddInformation(string inforMessage) {
			if (m_infoMessages == null)
				m_infoMessages = new List<string>();

			m_infoMessages.Add(inforMessage);
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="format"></param>
		/// <param name="args"></param>
		protected internal void AddInformation(string format, params object[] args) {
			if (string.IsNullOrWhiteSpace(format))
				return;
			else
				AddInformation(string.Format(format, args));
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="action"></param>
		protected void ExecuteSafely(Action action) {
			ExecuteSafely(
				action,
				(ex) => {
					AddError(ex.FormatMessage());
				});
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="action"></param>
		/// <param name="exceptionHandler"></param>
		protected void ExecuteSafely(Action action, Action<Exception> exceptionHandler) {
			try {
				action();
			} catch (ApplicationException ex) {
				if (m_logger.IsDebugEnabled) {
					m_logger.Debug("Failed to execute action.", ex);
				}

				exceptionHandler(ex);
			}
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="categoryId"></param>
		/// <param name="value"></param>
		/// <returns></returns>
		protected string GetCodeTextFromValue(int categoryId, object value) {
			return GetCodeTextFromValue(CONST_CODE_FILE_NAME, categoryId, value);
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="codeFileName"></param>
		/// <param name="categoryId"></param>
		/// <param name="value"></param>
		/// <returns></returns>
		protected string GetCodeTextFromValue(string codeFileName, int categoryId, object value) {
			System.Diagnostics.Debug.Assert(codeFileName != null);

			codeFileName = codeFileName.Trim();

			if (!codeFileName.StartsWith("~/") && !System.IO.Path.IsPathRooted(codeFileName)) {
				codeFileName = "~/" + codeFileName;
			}

			var cp = new CodeProvider(Context.Request.MapPath(codeFileName), new WebCacheProvider(Context));
			return cp.GetTextFromValue(categoryId, value);
		}


		/// <summary>
		/// 
		/// </summary>
		/// <param name="e"></param>
		protected override void OnLoad(EventArgs e) {
			// Keep only ONE validator when multiple validators is not valid.
			if (!ClientScript.IsStartupScriptRegistered(GetType(), "AltValidator")) {
				ClientScript.RegisterStartupScript(GetType(), "AltValidator",
@"
// Replace validator.
if (typeof(ValidatorUpdateDisplay) != ""undefined"") {
	var old_ValidatorUpdateDisplay = ValidatorUpdateDisplay;

	ValidatorUpdateDisplay = function(val) {
		for (var i = 0, v; i < Page_Validators.length && (v = Page_Validators[i]) != val; i++) {
			if (v.controltovalidate == val.controltovalidate && !v.isvalid)
				val.isvalid = true;
		}
		old_ValidatorUpdateDisplay(val);
	};
}
", true);

				base.OnLoad(e);
			}
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="e"></param>
		protected override void OnPreRenderComplete(EventArgs e) {
			base.OnPreRenderComplete(e);

			MyMasterPage mp = null;
			var p = Master;
			while (p != null) {
				if (p is MyMasterPage) {
					mp = (MyMasterPage)p;
					break;
				} else {
					p = p.Master;
				}
			}

			if (mp != null) {
				mp.SubTitle = Title;
				mp.ErrorMessages = m_errorMessages == null ? new string[0] : m_errorMessages.ToArray();
				mp.WarningMessages = m_warningMessage == null ? new string[0] : m_warningMessage.ToArray();
				mp.InfoMessages = m_infoMessages == null ? new string[0] : m_infoMessages.ToArray();
			}
		}

		/// <summary>
		/// 
		/// </summary>
		private static byte[] SerializeObject(object obj) {
			if (obj == null)
				return null;

			using (var ms = new MemoryStream()) {
				var formatter = new BinaryFormatter();
				formatter.Serialize(ms, obj);
				return ms.ToArray();
			}
		}

		/// <summary>
		/// 
		/// </summary>
		private static object DeserializeObject(byte[] bytes) {
			object obj = null;
			if (bytes == null)
				return obj;
			using (var ms = new MemoryStream(bytes)) {
				var formatter = new BinaryFormatter();
				return formatter.Deserialize(ms);
			}
		}

		/// <summary>
		/// 
		/// </summary>
		/// <returns></returns>
		protected override object LoadPageStateFromPersistenceMedium() {
#if PROFILE
			var s0 = new System.Diagnostics.Stopwatch();
			s0.Start();
#endif
			var viewStateServerUrl = System.Configuration.ConfigurationManager.AppSettings["MyLib.ViewStateServer"];
			object ret = null;
			if (!string.IsNullOrWhiteSpace(viewStateServerUrl)) {
				var persister = Activator.GetObject(typeof(MyLib.Web.ViewStatePersister), viewStateServerUrl)
					as MyLib.Web.ViewStatePersister;
				var viewStateId = Convert.ToInt64(
					((System.Web.UI.Pair)base.LoadPageStateFromPersistenceMedium()).Second);
				ret = DeserializeObject(persister.Load(viewStateId));
			} else {

				ret = base.LoadPageStateFromPersistenceMedium();
			}

#if PROFILE
			s0.Stop();
			m_logger.DebugFormat("Loading page state cost {0} millseconds.", s0.ElapsedMilliseconds);
#endif
			return ret;
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="state"></param>
		protected override void SavePageStateToPersistenceMedium(object state) {
#if PROFILE
			var s0 = new System.Diagnostics.Stopwatch();
			s0.Start();
#endif
			var viewStateServerUrl = System.Configuration.ConfigurationManager.AppSettings["MyLib.ViewStateServer"];
			if (!string.IsNullOrWhiteSpace(viewStateServerUrl)) {
				var persister = Activator.GetObject(typeof(MyLib.Web.ViewStatePersister), viewStateServerUrl)
					as MyLib.Web.ViewStatePersister;
				var viewStateId = persister.Save(SerializeObject(state));
				base.SavePageStateToPersistenceMedium(viewStateId);
			} else {
				base.SavePageStateToPersistenceMedium(state);
			}

#if PROFILE
			s0.Stop();
			m_logger.DebugFormat("Loading page state cost {0} millseconds.", s0.ElapsedMilliseconds);
#endif
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="e"></param>
		protected override void OnUnload(EventArgs e) {
			base.OnUnload(e);

			// SessionFactory.DefaultInstance.EndTransaction();
		}

		/// <summary>
		/// 
		/// </summary>
		/// <param name="group"></param>
		/// <returns></returns>
		protected string[] GetCheckedValues(string group) {
			System.Diagnostics.Debug.Assert(!string.IsNullOrEmpty(group));

			var checkedValues = this.Request[group];
			if (string.IsNullOrEmpty(checkedValues))
				return new string[0];
			else
				return checkedValues.Split(',');
		}
	} // end of MyPage.
}
